package model.elements;

import model.collisions.CollisionCategory;
import model.elements.attributes.Coordinate2D;
import model.elements.attributes.Damage;
import model.elements.attributes.Speed;
import model.elements.behaviours.Mobile;
import model.elements.behaviours.TakesDamage;
import model.elements.behaviours.Weapon;
import model.elements.commands.ElementCommandFactory;
import model.elements.states.life.Dying;
import model.elements.states.movement.ElementMovementState;
import model.elements.states.movement.MovingRight;
import model.elements.states.movement.Stopped;
import model.exceptions.CommandFactoryIsNotReady;
import model.exceptions.ModelExceptions;
import model.movement.MovementEngine;

// TODO: Auto-generated Javadoc
/**
 * The Class Bullet.
 */
public class Bullet extends TemporalSingleCommandElement implements Weapon, TakesDamage, Mobile {

	/** The m_moved once. */
	private boolean 				m_movedOnce;
	
	/** The m_speed. */
	private Speed 					m_speed;
	
	/** The m_movement sate. */
	private ElementMovementState 	m_movementSate;
	
	/** The m_facing to. */
	private ElementMovementState 	m_facingTo;
	
	/** The m_blast type. */
	private CollisionCategory 		m_blastType;
	
	/** The m_blast damage. */
	private Damage 					m_blastDamage;
	
	/** The m_blast range. */
	private int						m_blastRange;
	
	/**
	 * Inits the.
	 *
	 * @param blastType the blast type
	 * @param speed the speed
	 * @param blastDamage the blast damage
	 * @param blastRange the blast range
	 */
	private void init(CollisionCategory blastType, double speed, Damage blastDamage, int blastRange) {
		m_movedOnce 	= false;
		m_speed 		= new Speed(speed);
		m_movementSate	= new Stopped();
		m_facingTo		= new MovingRight();
		m_blastType		= blastType;
		m_blastDamage	= blastDamage;
		m_lifeState.setCategory(CollisionCategory.C_BULLET);
		m_blastRange	= blastRange;
	}
	
	/**
	 * Instantiates a new bullet.
	 *
	 * @param position the position
	 * @param direction the direction
	 * @throws ModelExceptions the model exceptions
	 */
	public Bullet( 
			Coordinate2D position, 
			ElementMovementState direction 
	) throws ModelExceptions {
		super( position, ElementCommandFactory.getElementMove( direction ) );
		init( CollisionCategory.C_L1_EXPLOTION, 1.0, new Damage(999), 5 );
	}
	
	/**
	 * Instantiates a new bullet.
	 *
	 * @param position the position
	 * @param direction the direction
	 * @param blastType the blast type
	 * @param Speed the speed
	 * @throws ModelExceptions the model exceptions
	 */
	public Bullet( 
			Coordinate2D position, 
			ElementMovementState direction,
			CollisionCategory blastType, 
			double Speed 
	) throws ModelExceptions {
		super( position, ElementCommandFactory.getElementMove( direction ) );
		init( blastType, Speed, new Damage(999), 5 );
	}
	
	/**
	 * Instantiates a new bullet.
	 *
	 * @param position the position
	 * @param direction the direction
	 * @param blastType the blast type
	 * @param Speed the speed
	 * @param blastDamage the blast damage
	 * @param blastRange the blast range
	 * @throws ModelExceptions the model exceptions
	 */
	public Bullet( 
			Coordinate2D position, 
			ElementMovementState direction,
			CollisionCategory blastType, 
			double Speed,
			Damage blastDamage,
			int blastRange
	) throws ModelExceptions {
		super( position, ElementCommandFactory.getElementMove( direction ) );
		init( blastType, Speed, blastDamage, blastRange );
	}

	/**
	 * Die.
	 */
	public void die() {
		if( m_movedOnce )
			m_lifeState = new Dying();		
	}
	
	/* (non-Javadoc)
	 * @see model.elements.TemporalSingleCommandElement#update()
	 */
	@Override
	public void update() throws ModelExceptions
	{
		super.update();
		m_movedOnce = true;
	}
	
	/* (non-Javadoc)
	 * @see model.elements.TemporalSingleCommandElement#onDeath()
	 */
	@Override
	public void onDeath() throws ModelExceptions {
		ElementCommandFactory.getElementCreateBlast(CollisionCategory.C_L1_EXPLOTION, 3).execute(this);		
	}
	
	/* (non-Javadoc)
	 * @see model.elements.behaviours.TakesDamage#takeDamage(model.elements.attributes.Damage)
	 */
	@Override
	public void takeDamage( Damage damage ) throws CommandFactoryIsNotReady
	{	
	}

	/* (non-Javadoc)
	 * @see model.elements.behaviours.Weapon#setPosition(model.elements.attributes.Coordinate2D)
	 */
	@Override
	public void setPosition(Coordinate2D position) {
		m_currentPosition = position;
	}

	/* (non-Javadoc)
	 * @see model.elements.behaviours.Mobile#getSpeed()
	 */
	@Override
	public Speed getSpeed() {
		return m_speed;
	}
	
	/**
	 * Sets the speed.
	 *
	 * @param speed the new speed
	 */
	protected void setSpeed(double speed) {
		m_speed.setBaseSpeed(speed);
	}

	/* (non-Javadoc)
	 * @see model.elements.behaviours.Mobile#getNextPosition()
	 */
	@Override
	public Coordinate2D getNextPosition() {
		return MovementEngine.getNextPositionForNonAcceleratedMovement(
				m_currentPosition, 
				m_movementSate, 
				m_speed
		);
	}
	
	/* (non-Javadoc)
	 * @see model.elements.behaviours.Mobile#getNextTile()
	 */
	@Override
	public Coordinate2D getNextTile()
	{
		return MovementEngine.getNextPositionForNonAcceleratedMovement(
				m_currentPosition, 
				m_movementSate, 
				new Speed(1.0)
		);
	}

	/* (non-Javadoc)
	 * @see model.elements.behaviours.Mobile#setMovementState(model.elements.states.movement.ElementMovementState)
	 */
	@Override
	public void setMovementState(ElementMovementState movementState) {
		m_facingTo = movementState.getFacingTo(m_movementSate);
		m_movementSate = movementState;
	}

	/* (non-Javadoc)
	 * @see model.elements.behaviours.Mobile#getDirection()
	 */
	@Override
	public ElementMovementState getDirection() {
		return m_facingTo;
	}

	/* (non-Javadoc)
	 * @see model.elements.behaviours.Weapon#getBlastType()
	 */
	@Override
	public CollisionCategory getBlastType() {
		return m_blastType;
	}

	/* (non-Javadoc)
	 * @see model.elements.behaviours.Weapon#getDamage()
	 */
	@Override
	public Damage getDamage() {
		return m_blastDamage;
	}

	/* (non-Javadoc)
	 * @see model.elements.behaviours.Weapon#getBlastRange()
	 */
	@Override
	public int getBlastRange()
	{
		return m_blastRange;
	}

}
